function varargout = addModelFolder(modelName, varargin)
% 函数功能：创建新的模型文件夹
%   addModelFolder 基于设计文件夹模板创建新的模型文件夹。除非指定第二个参数，
%   否则模型假定为多实例化的。
%
%   语法：
%   addModelFolder(ModelName)
%   addModelFolder(ModelName, 'Nonreusable')
%   addModelFolder(ModelName, 'ProjectObj', prj)
%   addModelFolder(ModelName, 'Nonreusable', 'ProjectObj', prj)
%
%   输入参数：
%   modelName - 要创建的模型名称
%   varargin - 可选参数
%     'Nonreusable' - 位置参数，指定模型不可重用
%     'ProjectObj' - Name-Value参数，指定项目对象（默认调用currentProject()）
%
%   输出参数：
%   varargout - 可变输出参数，包含创建结果结构体
%
%   
% 从配置文件读取是否使用数据字典的设置（基于DO-178规则第2条：不使用hardcode值）
try
    [useDictConfig, ~] = configManager.getConfigValue('UseDataDictionary');
    if islogical(useDictConfig) || isnumeric(useDictConfig)
        slddLink = logical(useDictConfig);
    else
        % 配置值异常时使用默认值
        slddLink = true;
        warning('addModelFolder:ConfigWarning', ...
            'UseDataDictionary配置值格式异常，使用默认值true');
    end
catch
    % 配置读取失败时使用默认值
    slddLink = true;
    warning('addModelFolder:ConfigWarning', ...
        '无法从配置文件读取UseDataDictionary，使用默认值true');
end

% 检查输入参数数量
if nargin < 1
    % 如果没有提供模型名称，则查询模型名称
    modelName = char(inputdlg('Enter model name.', 'Model Name', [1 50]));
    if isempty(modelName)
        return;  % 如果用户取消，则返回
    end
    % 查询模型是否为多实例化的
    reuse = strcmpi(questdlg('Is the model multi-instantiable?', 'Reusability', 'Yes', 'No', 'Yes'), 'Yes');
else
    % 解析 Name-Value 参数
    p = inputParser;
    addOptional(p, 'ReuseFlag', '', @ischar);  % 'Nonreusable' 标志
    addParameter(p, 'ProjectObj', [], @(x) isempty(x) || isa(x, 'matlab.project.Project'));
    parse(p, varargin{:});
    
    % 检查模型是否为多实例化的
    if ~isempty(p.Results.ReuseFlag)
        reuse = false;  % 如果指定了 'Nonreusable'，则不可重用
    else
        reuse = true;   % 否则默认为可重用
    end
    
    % 获取项目对象
    if ~isempty(p.Results.ProjectObj)
        prj = p.Results.ProjectObj;  % 使用传入的项目对象
    else
        prj = currentProject();  % 否则获取当前项目
    end
end

% 检查模型名称是否有效
if ~isvarname(modelName)
    error([modelName, ' is an invalid model name. The model name must be a valid MATLAB variable name. See MATLAB help documentation for variable naming rules.']);
end

% 检查模型是否已存在
if exist(modelName)
    error(['Model ''', modelName, ''' already exists.']);
end

try
    % 关闭可能仍在内存中的模型和数据字典
    bdclose(modelName);
    % 注释掉的代码：关闭数据字典
%     Simulink.data.dictionary.closeAll(['DD_', modelName, '.sldd'], '-discard');
    % 添加配置路径
    addpath(fullfile(fileparts(mfilename('fullpath')), '..', '..', '..', 'project_configuration'));
    Simulink.data.dictionary.closeAll([ProjectNamingManager.getNameStr('model data', modelName), '.sldd'], '-discard');
catch
    % 忽略关闭错误
end

% 创建新的模型文件夹
% 如果在交互模式下没有设置prj，则在此处获取
if ~exist('prj', 'var')
    prj = currentProject();  % 获取当前项目
end
srcDirName = ProjectPathManager.getDirPath('model root', 'sample_model');  % 源目录路径
dstDirName = ProjectPathManager.getDirPath('model root', modelName);      % 目标目录路径
copyfile(srcDirName, dstDirName);  % 复制文件夹

% 创建新模型
model = Simulink.createFromTemplate([ProjectNamingManager.getNameStr('model template'), '.sltx'], 'Name', modelName);
save_system(model, fullfile(ProjectPathManager.getDirPath('model', modelName), modelName));  % 保存模型

% 如果模型是多实例化的，创建MATLAB数据文件以在模型工作空间中定义模型数据
if reuse
    % 注释掉的代码：使用硬编码路径
%     fid = fopen(fullfile(dstDirName, 'specification', 'data', ['localDD_', modelName, '.m']), 'w');
    fid = fopen(fullfile(ProjectPathManager.getDirPath('model data', modelName), [ProjectNamingManager.getNameStr('local model data', modelName), '.m']), 'w');
    fprintf(fid, '%% Define data to be loaded into model workspace here.\n');  % 写入注释
    fclose(fid);
end

% 如果启用数据字典链接
if slddLink
    % 如果模型不是多实例化的，创建Simulink数据字典文件以定义模型数据
    % 此字典必须包含包含正确模型配置的字典
    dataDictionary = Simulink.data.dictionary.create(fullfile(ProjectPathManager.getDirPath('model data', modelName), [ProjectNamingManager.getNameStr('model data', modelName), '.sldd']));
    if reuse
        dataDictionary.addDataSource('csMultiInstance.sldd');  % 添加多实例数据源
    else
        dataDictionary.addDataSource('csSingleInstance.sldd');  % 添加单实例数据源
    end
    dataDictionary.saveChanges;  % 保存更改
else
    % 如果模型不是多实例化的，创建MATLAB数据文件以在基础工作空间中定义模型数据
    if ~reuse
        fid = fopen(fullfile(ProjectPathManager.getDirPath('model data', modelName), [ProjectNamingManager.getNameStr('model data', modelName), '.m']), 'w');
        fprintf(fid, 'if ~exist(''%s__'', ''var'')\n', ['DD_', modelName]);  % 写入条件检查
        fprintf(fid, '    %s__ = true;\n', ['DD_', modelName]);              % 写入变量初始化
        fprintf(fid, '    %% Define data to be loaded into base workspace here.\n');  % 写入注释
        fprintf(fid, 'end\n');  % 写入结束标记
        fclose(fid);
    end
end

% 创建用于打开模型的脚本
fid = fopen(fullfile(ProjectPathManager.getDirPath('model', modelName), [ProjectNamingManager.getNameStr('load command', modelName), '.m']), 'w');
if reuse
    fprintf(fid, '%% Data is automatically loaded into model workspace.\n');  % 写入注释
else
    fprintf(fid, '%% Uncomment the next line to load data into base worksapce if data is\n');  % 写入注释
    fprintf(fid, '%% defined using MATLAB data file instead of Simulink data dictionary file.\n');  % 写入注释
    if slddLink
        fprintf(fid, '%% ');  % 如果使用数据字典，则注释掉数据加载行
    end
    fprintf(fid, '%s;\n', ['DD_', modelName]);  % 写入数据加载命令
end
fprintf(fid, '%s;\n',  modelName);  % 写入模型打开命令
fclose(fid);

% 为新模型添加代码验证文件夹
codeDirs = {ProjectPathManager.getDirPath('code coverage', modelName), ...      % 代码覆盖率目录
            ProjectPathManager.getDirPath('code metrics', modelName), ...        % 代码度量目录
            ProjectPathManager.getDirPath('code prover', modelName), ...         % 代码证明目录
            ProjectPathManager.getDirPath('code review', modelName), ...         % 代码审查目录
            ProjectPathManager.getDirPath('code standards', modelName), ...      % 代码标准目录
            ProjectPathManager.getDirPath('bug finder', modelName), ...          % Bug查找器目录
            ProjectPathManager.getDirPath('test results', modelName)};           % 测试结果目录
for dirIdx = 1:length(codeDirs)
    mkdir(codeDirs{dirIdx});  % 创建目录
end

try
    % 将新文件夹添加到项目
    prj.addFolderIncludingChildFiles(dstDirName);  % 添加主模型文件夹
    for dirIdx = 1:length(codeDirs)
        prj.addFolderIncludingChildFiles(codeDirs{dirIdx});  % 添加代码验证文件夹
    end
    
    % 性能优化：检测MATLAB版本，R2025a+支持批量路径添加
    % 基于开发规则：优化项目API调用次数，大幅提升创建性能
    isR2025aOrLater = ~isMATLABReleaseOlderThan('R2025a');
    
    % 将新文件夹添加到项目路径
    modelPaths = genpath(dstDirName);  % 生成模型路径
    dirList = regexp(modelPaths, pathsep, 'split');  % 分割路径
    dirList = union(dirList, codeDirs);  % 合并目录列表
    
    if isR2025aOrLater
        % ==================== R2025a+ 批量优化版本 ====================
        % 过滤出有效的文件夹路径
        validDirs = {};
        for dirIdx = 1:length(dirList)
            if isfolder(dirList{dirIdx})
                validDirs{end+1} = dirList{dirIdx}; %#ok<AGROW>
            end
        end
        
        % 批量添加所有路径（性能优化核心：1次API调用代替几十次）
        if ~isempty(validDirs)
            try
                prj.addPath(validDirs);
                fprintf('✅ 批量添加了 %d 个路径到项目（R2025a优化）\n', length(validDirs));
            catch ME
                warning(['批量添加路径失败: ', ME.message, '，回退到逐个添加']);
                % 回退到逐个添加
                for pathIdx = 1:length(validDirs)
                    try
                        prj.addPath(validDirs{pathIdx});
                    catch
                        warning(['Unable to add ''', validDirs{pathIdx}, ''' to project path.']);
                    end
                end
            end
        end
        
    else
        % ==================== 早期版本兼容模式 ====================
        for dirIdx = 1:length(dirList)
            if isfolder(dirList{dirIdx})
                prj.addPath(dirList{dirIdx});  % 添加文件夹到项目路径
            end
        end
    end
    
    % 添加控制类别和生命周期数据标签
    subFolder = prj.findFile(ProjectPathManager.getDirPath('model', modelName));  % 查找模型文件夹
    subFolder.addLabel('Control Category', 'CC1');           % 添加控制类别标签
    subFolder.addLabel('Life Cycle Data', 'MB.11.10 SDD');   % 添加软件设计文档标签
    subFolder.addLabel('Life Cycle Data', 'MB.11.21 TD');    % 添加测试文档标签
    subFolder = prj.findFile(ProjectPathManager.getDirPath('test cases', modelName));  % 查找测试用例文件夹
    subFolder.addLabel('Control Category', 'CC1');           % 添加控制类别标签
    subFolder.addLabel('Life Cycle Data', 'MB.11.13 SVCP');  % 添加软件验证用例和程序标签
    subFolder.addLabel('Life Cycle Data', 'MB.11.21 TD');    % 添加测试文档标签
    subFolder = prj.findFile(ProjectPathManager.getDirPath('model verification', modelName));  % 查找验证结果文件夹
    subFolder.addLabel('Control Category', 'CC2');           % 添加控制类别标签
    subFolder.addLabel('Life Cycle Data', 'MB.11.14 SVR');   % 添加软件验证结果标签
    subFolder.addLabel('Life Cycle Data', 'MB.11.21 TD');    % 添加测试文档标签

    % 添加设计模型标签
    modelFile = prj.findFile(fullfile(ProjectPathManager.getDirPath('model', modelName), [modelName, '.slx']));  % 查找模型文件
    modelFile.addLabel('Design Model', 'Unit');  % 添加设计模型标签
catch
    error(['Unable to add ''', dstDirName, ''' to project.']);  % 抛出错误
end

% 如果模型是多实例化的，从数据源将数据加载到模型工作空间
if reuse
    ws = get_param(model, 'ModelWorkspace');  % 获取模型工作空间
    ws.DataSource = 'MATLAB Code';            % 设置数据源为MATLAB代码
    ws.MATLABCode = ['localDD_', modelName, ';'];  % 设置MATLAB代码
    ws.reload();  % 重新加载工作空间
end

% 如果启用数据字典链接
if slddLink
    % 将模型链接到数据字典
    set_param(model, 'DataDictionary', ['DD_', modelName, '.sldd']);  % 设置数据字典
    set_param(model, 'EnableAccessToBaseWorkspace', 'off');           % 禁用对基础工作空间的访问
end

% 创建适当的模型配置引用并将其附加到模型
Reference = Simulink.ConfigSetRef;  % 创建配置集引用
if reuse
    Reference.SourceName = 'csMultiInstance';    % 设置多实例配置源
else
    Reference.SourceName = 'csSingleInstance';   % 设置单实例配置源
end
attachConfigSet(modelName, Reference);           % 附加配置集
setActiveConfigSet(modelName, 'Reference');      % 设置活动配置集

% 重新保存模型
save_system(model);

% 设置成功消息
result.Message = ['New model folder ', dstDirName, ' is successfully created and added to the current project.'];
% 如果有输出参数，则设置返回值
if nargout > 0
    varargout{1} = result;
end
% 显示结果消息
disp(result.Message);

end
